package wator.view.swing.jogl;

import java.awt.Dimension;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.swing.JPanel;

import wator.model.Agent;
import wator.model.Population;
import wator.model.Simulation;
import wator.view.swing.SwingUI;

import com.jogamp.opengl.util.gl2.GLUT;

public class Jogl extends JPanel implements GLEventListener {
	private double theta = 0;
	private double s = 0;
	private double c = 0;
	private SwingUI swingUI;
	private GLU glu;
	private GLUT glut;
	private Dimension canvasSize;
	private int camRotX;
	private int camRotY;
	private float camDistance;
	private final float INIT_CAM_DISTANCE = 50;
	private GLAutoDrawable drawable;
	
	public Jogl(SwingUI swingUI) {
		this.swingUI = swingUI;
		swingUI.setPop(Simulation.getInstance().getPopulation());
		canvasSize = swingUI.getCanvasSize();
		camRotX = 0;
		camRotY = 0;
		camDistance = INIT_CAM_DISTANCE;
	}
	
	@Override
	public void display(GLAutoDrawable drawable) {
		this.drawable = drawable;
		//setCamera(drawable, glu, 3);
		update();
	    render(drawable);
	}
	
	private void render(GLAutoDrawable drawable) {
	    
		GL2 gl = drawable.getGL().getGL2();
	    gl.glClearColor(0.694f, 0.875f, 0.953f, 1f);
	    gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
	    
	    float[] lightPos = { 2000,3000,2000,1 };        
	    float[] ambient = { 0.8f, 0.8f, 0.8f, 1f };   
	    float[] diffuse = { 1f, 1f, 1f, 1f };     
	    float[] specular = { 0.3f, 0.3f, 0.3f, 1f};

	    /*
	    gl.glEnable(GL2.GL_LIGHTING);
	    gl.glShadeModel(GL2.GL_SMOOTH);
	    gl.glEnable(GL2.GL_LIGHT0); 
	    
	    gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, ambient, 0);
	    gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, diffuse, 0);
	    gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION,lightPos, 0);
	    gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, specular, 0);
	     */
	    
	 // Set Ambient Lighting To Fairly Dark Light (No Color)
        float[] global_ambient = new float[]{0.3f, 0.3f, 0.3f, 1.0f};    
        // Set The Light Position
        float[] light0pos = new float[]{0.0f, 5.0f, 10.0f, 1.0f};    
        // More Ambient Light
        float[] light0ambient = new float[]{0.2f, 0.2f, 0.2f, 1.0f};    
        // Set The Diffuse Light A Bit Brighter
        float[] light0diffuse = new float[]{0.4f, 0.4f, 0.4f, 1.0f};    
        // Fairly Bright Specular Lighting
        float[] light0specular = new float[]{0.8f, 0.8f, 0.8f, 1.0f};    

        // And More Ambient Light
        float[] lmodel_ambient = new float[]{0.2f, 0.2f, 0.2f, 1.0f};      
        // Set The Ambient Light Model
        //gl.glLightModelfv(GL2.GL_LIGHT_MODEL_AMBIENT, lmodel_ambient, 0);    

        // Set The Global Ambient Light Model
        //gl.glLightModelfv(GL2.GL_LIGHT_MODEL_AMBIENT, global_ambient, 0);    
        // Set The Lights Position
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, light0pos, 0);        
        // Set The Ambient Light
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, light0ambient, 0);      
        // Set The Diffuse Light
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, light0diffuse, 0);      
        // Set Up Specular Lighting
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, light0specular, 0);      
        gl.glEnable(GL2.GL_LIGHTING);  // Enable Lighting
        gl.glEnable(GL2.GL_LIGHT0);  // Enable Light0

        gl.glShadeModel(GL2.GL_SMOOTH);  // Select Smooth Shading
        
	    setCamera(drawable, glu, 15);
	    	    
	    JoglDrawingStrategy.setDrawable(drawable);
	    JoglDrawingStrategy.setGLU(glu);
	    JoglDrawingStrategy.setGLUT(glut);
	    
	    Population pop = Simulation.getInstance().getPopulation();
	    synchronized (pop) {
	    	for (Agent agent : pop) {
	    		agent.draw();
	    	}
	    }
	}
	
	private void update() {
		switch(swingUI.getAnimationSpeed()) {
		case STOP: 
			c = 1;
			s = 1;
			break;
		case NORMAL:
			theta += 0.01;
			s = Math.sin(theta);
			c = Math.cos(theta);
			break;
		case FAST: 
			theta += 0.03;
			s = Math.sin(theta);
			c = Math.cos(theta);
			break;
		}
		
	}

	@Override
	public void dispose(GLAutoDrawable arg0) {
		// TODO Auto-generated method stub
	
	}

	@Override
	public void init(GLAutoDrawable drawable) {
		drawable.getGL().setSwapInterval(1);
		glu = new GLU();
		glut = new GLUT();
	}

	@Override
	public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
        GL2 gl = drawable.getGL().getGL2();
        gl.glViewport(0, 0, width, height);
    }
	
	public void show() {
		//display(th);
	}
	
	private void setCamera(GLAutoDrawable drawable, GLU glu, float distance) {
        // Change to projection matrix.
		GL2 gl = drawable.getGL().getGL2();
        gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glLoadIdentity();

        // Perspective.
        float widthHeightRatio = canvasSize.width / canvasSize.height;
        if (widthHeightRatio == 0) {
        	widthHeightRatio = 1.5f;
        }
        glu.gluPerspective(45, widthHeightRatio, 1, 1000);
        glu.gluLookAt(0, 0, camDistance, 0, 0, 0, 0, 1, 0);
        gl.glRotatef(camRotX, 1, 0, 0);
        gl.glRotatef(camRotY, 0, 1, 0);

        // Change back to model view matrix.
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();
    }
	
	public void rotateCamera(int degX, int degY) {
		camRotX += 3*degX;
		camRotY += 3*degY;
	}
	
	/**
	 * Zooms the camera away
	 * @param zoom positive number zooms in, negative zooms out
	 */
	public void zoomCamera(int zoom) {
		if (zoom >=0) 
			camDistance -= 0.5f;
		else {
			if (camDistance > 2)
				camDistance += 0.5;
		}
	}
	
	public void resetCamPos() {
		camRotX = 0;
		camRotY = 0;
		camDistance = INIT_CAM_DISTANCE;
	}
	
}
